package org.yanse.structures.stack.calculator;

public class InversePolish {
    private static Stack<Integer> numStack = new Stack<>();
    private static Stack<Character> symbolStack = new Stack<>();

    // 中缀转后缀表达式
    public static String afterTransit(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }

        if (!symbolStack.isEmpty()) {
            symbolStack.clear();
        }

        char[] chars = str.toCharArray();
        StringBuilder sb = new StringBuilder();
        int index = 0;
        for (char c : chars) {
            if (isNum(c)) {
                sb.append(c);
                continue;
            }

            if (c == ')') {
                while (symbolStack.peek() != '(') {
                    char symbol = symbolStack.pop();
                    sb.append(symbol);
                }
                symbolStack.pop();
                continue;
            }

            if (isSymbol(c)) {
                while (priority(c) <= symbolStackTopPriority()) {
                    sb.append(symbolStack.pop());
                }
            }

            symbolStack.add(c);
        }

        while (!symbolStack.isEmpty()) {
            sb.append(symbolStack.pop());
        }

        return sb.toString();
    }

    // 计算后缀表达式
    public static int calcAfter(String str) {
        if (str == null || str.length() == 0) {
            return 0;
        }

        if (!numStack.isEmpty()) {
            numStack.clear();
        }

        // 如果是数字入数栈
        // 如果是符号数栈出栈计算结果入数栈直到遍历完成
        for (char c : str.toCharArray()) {
            if (isNum(c)) {
                numStack.add(Integer.parseInt(String.valueOf(c)));
                continue;
            }

            calcOnce(c);
        }

        if (numStack.isEmpty()) {
            return 0;
        }

        return numStack.pop();
    }

    private static void calcOnce(char symbol) {
        int current = numStack.pop();
        int next = numStack.pop();
        switch (symbol) {
            case '+' :
                numStack.add(next + current);
                break;
            case '-' :
                numStack.add(next - current);
                break;
            case '*' :
                numStack.add(next * current);
                break;
            case '/' :
                if (current == 0) {
                    throw new ArithmeticException();
                }
                numStack.add(next / current);
                break;
        }
    }

    private static int symbolStackTopPriority() {
        if (symbolStack.isEmpty()) {
            return -1;
        }
        return priority(symbolStack.peek());
    }

    private static int priority(char symbol) {
        if (symbol == '+' || symbol == '-') {
            return 0;
        }

        if (symbol == '*' || symbol == '/') {
            return 1;
        }

        return -1;
    }

    private static boolean isSymbol(char symbol) {
        return symbol == '+' || symbol == '-' || symbol == '*' || symbol == '/';
    }

    private static boolean isNum(char num) {
        return num >= '0' && num <= '9';
    }

    // 中缀转前缀表达式
    public static String beforeTransfer(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }

        if (!symbolStack.isEmpty()) {
            symbolStack.clear();
        }

        char[] chars = str.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = chars.length - 1; i >= 0; i--) {
            char c = chars[i];
            if (isNum(c)) {
                sb.append(c);
                continue;
            }

            if (c == '(') {
                while (symbolStack.peek() != ')') {
                    char symbol = symbolStack.pop();
                    sb.append(symbol);
                }
                symbolStack.pop();
                continue;
            }

            if (isSymbol(c)) {
                while (priority(c) <= symbolStackTopPriority()) {
                    sb.append(symbolStack.pop());
                }
            }

            symbolStack.add(c);
        }

        while (!symbolStack.isEmpty()) {
            sb.append(symbolStack.pop());
        }

        return sb.reverse().toString();
    }

    public static int calcBefore(String str) {
        if (str == null || str.length() == 0) {
            return 0;
        }

        if (!numStack.isEmpty()) {
            numStack.clear();
        }

        char[] chars = str.toCharArray();
        for (int i = chars.length -1; i >= 0; i--) {
            char c = chars[i];
            if (isNum(c)) {
                numStack.add(Integer.parseInt(String.valueOf(c)));
                continue;
            }
            calcOnce(c);
        }

        if (numStack.isEmpty()) {
            return 0;
        }

        return numStack.pop();
    }
}
